home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Math / Basex.php next >
PHP Script  |  2004-03-24  |  12KB  |  416 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Dave Mertens <dmertens@zyprexia.com>                        |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Basex.php,v 1.6 2003/06/04 14:48:44 et Exp $
  20.  
  21. require_once "PEAR.php";
  22.  
  23. if (!defined('MATH_BASEX_MATHEXTENSION')) {
  24.     if (PEAR::loadExtension('bcmath')) {
  25.         define('MATH_BASEX_MATHEXTENSION', 'bcmath');
  26.     } elseif (PEAR::loadExtension('gmp')) {
  27.         define('MATH_BASEX_MATHEXTENSION', 'gmp');
  28.     } else {
  29.         define('MATH_BASEX_MATHEXTENSION', 'none');
  30.     }
  31. }
  32.  
  33. /**
  34. * base X coding class
  35. *
  36. * I noticed that value of an int is different on most systems. 
  37. * On my system (linux 2.4.18 with glibc 2.2.5) i can use 8-byte integers 
  38. * (also called int64 or int8)
  39. * On my laptop (Windows 2000) i only could use numbers up to 4-byte (32 bit) 
  40. * integers.
  41. * So you might want to test this first!
  42. *
  43. * Note that you can without much effort also use the bcmath extentions to 
  44. * increase the length of your numbers.
  45. *
  46. * @author Dave Mertens <dmertens@zyprexia.com>
  47. * @version 0.3
  48. * @access public
  49. * @package Math_Basex
  50. * @category Math
  51. */
  52. class Math_Basex
  53. {
  54.     /**
  55.     * @var character base set
  56.     * @access private;
  57.     */
  58.     var $_baseChars;
  59.  
  60.     /**
  61.     * @var base length (for binair 2, dec 10, hex 16, yours ??)
  62.     * @access private;
  63.     */
  64.     var $_length;
  65.     
  66.     /**
  67.     * Constructor for class
  68.     *
  69.     * @param tokens string Character base set (Each character is only allowed 
  70.     *                                          once!)
  71.     * @return void
  72.     */
  73.     function Math_Basex($tokens = "")
  74.     {
  75.         //set initial length
  76.         $this->_length = 0;
  77.         
  78.         //if we did get already a character set, set it..
  79.         if (!empty($tokens)) {
  80.             $this->setBase($tokens);
  81.         }
  82.     }
  83.             
  84.     
  85.     /**
  86.     * Change the character base set. Behaves the same way the constructor does.
  87.     *
  88.     * @param tokens string Character base set (Each character is only allowed 
  89.     *                                          once!)
  90.     * @return void
  91.     * @access public
  92.     */
  93.     function setBase($tokens)
  94.     {
  95.         if (!$this->_checkBase($tokens)) {
  96.             return PEAR::raiseError("Each character is only allowed once");
  97.         }
  98.         $this->_baseChars = $tokens;
  99.         $this->_length = strlen($tokens);
  100.         return true;
  101.     }
  102.     
  103.     /**
  104.     * toBase translates a decimal (base 10) number into your base 'code'
  105.     *
  106.     * @param number (int64 or double without floats, both are 8-byte number 
  107.     *         types). This allows you to use numbers up to 18446744073709551616.
  108.     * @return string encoded 'code' of yout decimal number
  109.     */
  110.     function toBase($number)
  111.     {
  112.         if (!is_numeric($number)) {
  113.             return PEAR::raiseError("You must supply a decimal number");
  114.         }
  115.             
  116.         if ($this->_length == 0) {
  117.             return PEAR::raiseError("Character base isn't defined yet..");
  118.         }
  119.         if (is_float($number)) {
  120.             $number = ltrim(sprintf('%22.0f',$number));
  121.         }
  122.  
  123.         $code = "";
  124.         do {
  125.             $this->_splitnumber($number, $full, $mod);
  126.             $code = $this->_getToken($mod) . $code;
  127.             $number = $full;
  128.         } while ($number > 0);
  129.         
  130.         return $code;
  131.         
  132.     }
  133.     
  134.     /**
  135.     * toDecimal decodes the baseX 'code' back to a decimal number
  136.     *
  137.     * @param string code to decode
  138.     * @return int64 decimal (base 10) number
  139.     */
  140.     function todecimal($code)
  141.     {
  142.         $length = strlen($code);
  143.         $total = 0;
  144.         
  145.         if (strspn($code, $this->_baseChars) != $length) {
  146.             return PEAR::raiseError("Your Base X code contains invalid"
  147.                                    ." characters");
  148.         }
  149.  
  150.         for ($i=0; $i < $length; $i++) {
  151.             $sum = $this->_getNumber($code[$length - $i - 1]) * 
  152.                                      $this->_pow($this->_length, $i);
  153.             $total = $this->_add($total,$sum);
  154.         }
  155.         
  156.         return $total;
  157.     }
  158.     
  159.     /**
  160.     * Returns the base scale. Note that this is onyl the count of the 
  161.     * characters used for the encoding and decoding.
  162.     * Please do not use base_convert with this class, because it might result 
  163.     * in rare results
  164.     *
  165.     * @access public
  166.     * @return integer
  167.     */
  168.     function getBase()
  169.     {
  170.         return $this->_length;
  171.     }
  172.     
  173.     /**
  174.     * Validates whether each character is unique
  175.     *
  176.     * @param string tokens Character base set
  177.     * @access private
  178.     * @return boolean true if all characters are unique
  179.     */
  180.     function _checkBase($tokens)
  181.     {
  182.         $length = strlen($tokens);
  183.         for ($i=0; $i < $length; $i++) {
  184.             if (substr_count($tokens, $tokens[$i]) > 1)
  185.                 return false;    //character is specified more than one time!
  186.         }
  187.         
  188.         //if we come here, all characters are unique
  189.         return true;
  190.     }
  191.     
  192.     /**
  193.     * Helper function for encoding function. 
  194.     *
  195.     * @access private;
  196.     * @param number integer number to spilt for base conversion
  197.     * @param full integer non-float, unrounded number (will be passed as 
  198.     *                     reference)
  199.     * @param modules float floating number between 0 and 1 
  200.     *                     (will be passed as reference)
  201.     *
  202.     * @return void
  203.     */
  204.     function _splitNumber($number, &$full, &$modules)
  205.     {
  206.         $full = $this->_div($number, $this->_length);
  207.         $modules = $this->_mod($number, $this->_length);
  208.     }
  209.  
  210.     /**
  211.     * Helper function; Returns character at position x
  212.     *
  213.     * @param oneDigit integer number between 0 and basex->getBase()
  214.     * @return character from base character set
  215.     * @access private;
  216.     */
  217.     function _getToken($oneDigit)
  218.     {
  219.         return substr($this->_baseChars, $oneDigit, 1);
  220.     }
  221.     
  222.     /**
  223.     * Helper function; Returns position of character X
  224.     *
  225.     * @param oneDigit string Character in base character set
  226.     * @return integer number between 0 and basex->getBase()
  227.     * @access private;
  228.     */
  229.     function _getNumber($oneDigit)
  230.     {
  231.         return strpos($this->_baseChars, $oneDigit);
  232.     }    
  233.  
  234.     /**
  235.     * Add two numbers, utilize Math extensions
  236.     *
  237.     * @param mixed a First operand
  238.     * @param mixed b Second operand
  239.     * @return mixed
  240.     * @access private
  241.     */
  242.     function _add($a, $b)
  243.     {
  244.         switch (MATH_BASEX_MATHEXTENSION) {
  245.         case 'bcmath':
  246.             return bcadd($a, $b);
  247.         case 'gmp':
  248.             return gmp_strval(gmp_add($a, $b));
  249.         case 'none':
  250.             return $a + $b;
  251.         }
  252.     }
  253.  
  254.     /**
  255.     * Multiply two numbers, utilize Math extensions
  256.     *
  257.     * @param mixed a First operand
  258.     * @param mixed b Second operand
  259.     * @return mixed
  260.     * @access private
  261.     */
  262.     function _mul($a, $b)
  263.     {
  264.         switch (MATH_BASEX_MATHEXTENSION) {
  265.         case 'bcmath':
  266.             return bcmul($a, $b);
  267.         case 'gmp':
  268.             return gmp_strval(gmp_mul($a, $b));
  269.         case 'none':
  270.             return $a * $b;
  271.         }
  272.  
  273.     }
  274.  
  275.     /**
  276.     * Return the modulo of two numbers, utilize Math extensions
  277.     *
  278.     * @param mixed a First operand
  279.     * @param mixed b Second operand
  280.     * @return mixed
  281.     * @access private
  282.     */
  283.     function _mod($a, $b)
  284.     {
  285.         switch (MATH_BASEX_MATHEXTENSION) {
  286.         case 'bcmath':
  287.             return bcmod($a, $b);
  288.         case 'gmp':
  289.             return gmp_strval(gmp_mod($a, $b));
  290.         case 'none':
  291.             return $a % $b;
  292.         }
  293.     }
  294.  
  295.     /**
  296.     * Divide two integers, utilize Math extensions
  297.     *
  298.     * @param mixed a First operand
  299.     * @param mixed b Second operand
  300.     * @return mixed
  301.     * @access private
  302.     */
  303.     function _div($a, $b)
  304.     {
  305.         switch (MATH_BASEX_MATHEXTENSION) {
  306.         case 'bcmath':
  307.             return bcdiv($a, $b);
  308.         case 'gmp':
  309.             return gmp_strval(gmp_div($a, $b));
  310.         case 'none':
  311.             return floor($a / $b);
  312.         }
  313.     }
  314.  
  315.     /**
  316.     * Raise one number to the power of the other, utilize Math extensions
  317.     *
  318.     * @param mixed a First operand
  319.     * @param mixed b Second operand
  320.     * @return mixed
  321.     * @access private
  322.     */
  323.     function _pow($a, $b)
  324.     {
  325.         switch (MATH_BASEX_MATHEXTENSION) {
  326.         case 'bcmath':
  327.             return bcpow($a, $b);
  328.         case 'gmp':
  329.             return gmp_strval(gmp_pow($a, $b));
  330.         case 'none':
  331.             return pow($a,$b);
  332.         }
  333.     }
  334.  
  335.     /**
  336.     * Returns a common set of digits (0-9A-Za-z), length is given as parameter
  337.     *
  338.     * @param int length Optional How many characters to return, defaults to 62.
  339.     * @return string
  340.     * @access public
  341.     */
  342.     function stdBase($n = 62) 
  343.     {
  344.         return substr("0123456789"
  345.                      ."ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  346.                      ."abcdefghijklmnopqrstuvwxyz", 0, $n);
  347.     }
  348.  
  349.     /**
  350.     * Converts a number from one base into another. May be called statically.
  351.     * 
  352.     * @param mixed number The number to convert
  353.     * @param int from_base The base to convert from
  354.     * @param int to_base The base to convert to
  355.     * @param string from_cs Optional character set of the number that is
  356.     *                                converted
  357.     * @param string to_cs Optional character set of the target number
  358.     * @return string
  359.     * @access public
  360.     */
  361.     function baseConvert($number, $from_base, $to_base, 
  362.                           $from_cs = null, $to_cs = null)
  363.     {
  364.         if (isset($this)) {
  365.             $obj = &$this;
  366.         } else {
  367.             $obj = &Math_Basex::instance();
  368.         }
  369.         if (!isset($from_cs)) {
  370.             $from_cs = $obj->stdBase();
  371.         }
  372.         if (!isset($to_cs)) {
  373.             $to_cs = $obj->stdBase();
  374.         }
  375.         if (strlen($from_cs) < $from_base) {
  376.             return PEAR::raiseError('Character set isn\'t long enough for the'
  377.                                    .'given base.');
  378.         }
  379.         if (strlen($to_cs) < $to_base) {
  380.             return PEAR::raiseError('Character set isn\'t long enough for the'
  381.                                    .'given base.');
  382.         }
  383.         $from_cs = substr($from_cs, 0, $from_base);
  384.         $to_cs   = substr($to_cs,   0, $to_base);
  385.         if ($tmp = $obj->setBase($from_cs) !== true) {
  386.             return $tmp;
  387.         }
  388.         $number = $obj->toDecimal($number);
  389.         if (PEAR::isError($number)) {
  390.             return $number;
  391.         }
  392.         if ($tmp = $obj->setBase($to_cs) !== true) {
  393.             return $tmp;
  394.         }
  395.         $number = $obj->toBase($number);
  396.         return $number;
  397.     }
  398.  
  399.     /**
  400.     * Singleton method, call statically
  401.     *
  402.     * @return object
  403.     * @access public
  404.     */
  405.     function &instance()
  406.     {
  407.         static $ins = null;
  408.         if (is_null($ins)) {
  409.             $ins = new Math_Basex;
  410.         }
  411.         return $ins;
  412.     }
  413. }
  414.  
  415. ?>
  416.